/*=============================================================================
    Spirit v1.6.0
    Copyright (c) 2001-2003 Joel de Guzman
    http://spirit.sourceforge.net/

    Permission to copy, use, modify, sell and distribute this software is
    granted provided this copyright notice appears in all copies. This
    software is provided "as is" without express or implied warranty, and
    with no claim as to its suitability for any purpose.
=============================================================================*/
#ifndef BOOST_SPIRIT_SYMBOLS_HPP
#define BOOST_SPIRIT_SYMBOLS_HPP

///////////////////////////////////////////////////////////////////////////////
#include <string>

#include "boost/ref.hpp"

#include "boost/spirit/core/parser.hpp"
#include "boost/spirit/core/composite/directives.hpp"

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

///////////////////////////////////////////////////////////////////////////////
//  Forward Declarations

namespace impl
{
    template <typename CharT, typename T>
    class tst;
}

template <typename T, typename SetT>
class symbol_inserter;

///////////////////////////////////////////////////////////////////////////////
//
//  symbols class
//
//      This class implements a symbol table. The symbol table holds a
//      dictionary of symbols where each symbol is a sequence of CharTs.
//      The template class can work efficiently with 8, 16 and 32 bit
//      characters. Mutable data of type T is associated with each
//      symbol.
//
//      The class is a parser. The parse member function returns
//      additional information in the symbol_match class (see below).
//      The additional data is a pointer to some data associated with
//      the matching symbol.
//
//      The actual set implementation is supplied by the SetT template
//      parameter. By default, this uses the tst class (see tst.ipp).
//
//      Symbols are added into the symbol table statically using the
//      construct:
//
//          sym = a, b, c, d ...;
//
//      where sym is a symbol table and a..d are strings. Example:
//
//          sym = "pineapple", "orange", "banana", "apple";
//
//      Alternatively, symbols may be added dynamically through the
//      member functor 'add' (see symbol_inserter below). The member
//      functor 'add' may be attached to a parser as a semantic action
//      taking in a begin/end pair:
//
//          p[sym.add]
//
//      where p is a parser (and sym is a symbol table). On success,
//      the matching portion of the input is added to the symbol table.
//
//      'add' may also be used to directly initialize data. Examples:
//
//          sym.add("hello", 1)("crazy", 2)("world", 3);
//
///////////////////////////////////////////////////////////////////////////////
template
<
    typename T = int,
    typename CharT = char,
    typename SetT = impl::tst<T, CharT>
>
class symbols
:   private SetT
,   public parser<symbols<T, CharT, SetT> >
{
public:

    typedef parser<symbols<T, CharT, SetT> > parser_base_t;
    typedef symbols<T, CharT, SetT> self_t;
    typedef self_t const& embed_t;
    typedef T symbol_data_t;
    typedef boost::reference_wrapper<T> symbol_ref_t;

    symbols();
    symbols(symbols const& other);
    ~symbols();

    symbols&
    operator=(symbols const& other);

    symbol_inserter<T, SetT> const&
    operator=(CharT const* str);

    template <typename ScannerT>
    struct result
    {
        typedef typename match_result<ScannerT, symbol_ref_t>::type type;
    };

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse_main(ScannerT const& scan) const
    {
        typedef typename ScannerT::iterator_t iterator_t;
        iterator_t first = scan.first;
        typename SetT::search_info result = SetT::find(scan);

        if (result.data)
            return scan.
                create_match(
                    result.length,
                    symbol_ref_t(*result.data),
                    first,
                    scan.first);
        else
            return scan.no_match();
    }

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse(ScannerT const& scan) const
    {
        typedef typename parser_result<self_t, ScannerT>::type result_t;
        return impl::implicit_lexeme_parse<result_t>
            (*this, scan, scan);
    }

    template < typename ScannerT >
    T* find(ScannerT const& scan) const
    { return SetT::find(scan).data; }

    symbol_inserter<T, SetT> const add;
};

///////////////////////////////////////////////////////////////////////////////
//
//  Symbol table utilities
//
//  add
//
//      adds a symbol 'sym' (string) to a symbol table 'table' plus an
//      optional data 'data' associated with the symbol. Returns a pointer to
//      the data associated with the symbol or NULL if add failed (e.g. when
//      the symbol is already added before).
//
//  find
//
//      finds a symbol 'sym' (string) from a symbol table 'table'. Returns a
//      pointer to the data associated with the symbol or NULL if not found
//
///////////////////////////////////////////////////////////////////////////////
template <typename T, typename CharT, typename SetT>
T*  add(symbols<T, CharT, SetT>& table, CharT const* sym, T const& data = T());

template <typename T, typename CharT, typename SetT>
T*  find(symbols<T, CharT, SetT> const& table, CharT const* sym);

///////////////////////////////////////////////////////////////////////////////
//
//  symbol_inserter class
//
//      The symbols class holds an instance of this class named 'add'.
//      This can be called directly just like a member function,
//      passing in a first/last iterator and optional data:
//
//          sym.add(first, last, data);
//
//      Or, passing in a C string and optional data:
//
//          sym.add(c_string, data);
//
//      where sym is a symbol table. The 'data' argument is optional.
//      This may also be used as a semantic action since it conforms
//      to the action interface (see action.hpp):
//
//          p[sym.add]
//
///////////////////////////////////////////////////////////////////////////////
template <typename T, typename SetT>
class symbol_inserter
{
public:

    symbol_inserter(SetT& set_)
    : set(set_) {}

    template <typename IteratorT>
    symbol_inserter const&
    operator()(IteratorT first, IteratorT const& last, T const& data = T()) const
    {
        set.add(first, last, data);
        return *this;
    }

    template <typename CharT>
    symbol_inserter const&
    operator()(CharT const* str, T const& data = T()) const
    {
        CharT const* last = str;
        while (*last)
            last++;
        set.add(str, last, data);
        return *this;
    }

    template <typename CharT>
    symbol_inserter const&
    operator,(CharT const* str) const
    {
        CharT const* last = str;
        while (*last)
            last++;
        set.add(str, last, T());
        return *this;
    }

private:

    SetT& set;
};

///////////////////////////////////////////////////////////////////////////////
}} // namespace boost::spirit

#include "boost/spirit/symbols/impl/symbols.ipp"
#endif
